/* Copyright (C) 2003, Charles Wang.
 * Author:  Charles Wang <charles@linux.net.cn>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANT; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public LIcense for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include  <sys/types.h>
#include  <sys/stat.h>
#include  <sys/mount.h>
#include  <errno.h>
#include  <fcntl.h>
#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>
#include  <unistd.h>
#include  <newt.h>
#include  "magicbooter.h"
#include  "newtutils.h"
#include  "utils.h"
#include  "mblog.h"

extern unsigned miinitrd_size;
extern umnt_info  re_ui;
extern int        re_ui_valid;
extern const char * bootiso_fn;
extern const char * hotfixdir;

#ifdef USE_UDEV
int load_hotfix(void) {
    struct stat sbuf;
    int  cpiofd;
    int  p[2];
    pid_t  pid;
    int  r, status;
    char *accpath;

    if (!mi_hotfix_fullpath[0]) {
        mblog("No hotfix available.\n");
        goto err_ret0;
    }

    accpath = mount_path(mi_hotfix_fullpath, &re_ui);
    if (accpath == NULL) {
        mblog("hotfix: mount_path failed.\n");
        goto err_ret0;
    }
    else {
        strcpy(mi_hotfix_fullpath, accpath);
        free(accpath);
    }

    if (stat(mi_hotfix_fullpath, &sbuf)) {
        mblog("Stat hotfix failed.\n");
        goto err_ret1;          /* hotfix not found */
    }

    mblog("Loading Hot Fix: %s\n", mi_hotfix_fullpath);
    cpiofd = open(mi_hotfix_fullpath, O_RDONLY);
    if (cpiofd < 0) {
	newtWinMessage("Error", "OK",
		       "Failed in opening hotfix file %s: %s",
		       mi_hotfix_fullpath, strerror(errno));
	goto  err_ret1;
    }

    pipe(p);
    if ((pid = fork()) < 0) {
	newtWinMessage("Error", "OK", "fork failed: %s", strerror(errno));
	goto  err_ret2;
    } else if (pid == 0) {
	/* Child process. */
	close(cpiofd);
	close(p[1]);
	dup2(p[0], 0);
	pipe(p);
	if ((pid = fork()) < 0) {
	    mblog("gzip process fork failed: %s\n", strerror(errno));
	    exit(1);
	} else if (pid == 0) {
	    close(p[1]);
	    dup2(p[0], 0);
            mkdir(hotfixdir, 0644);
            chdir(hotfixdir);
	    execl("/bin/cpio", "/bin/cpio", "-diu", NULL);
	    exit(1);
	}
	dup2(p[1], 1);
	close(p[0]);
	execl("/bin/gunzip", "/bin/gunzip", "-c", "-");
	exit(1);
    }
    close(p[0]);

    newt_copy_file(cpiofd, p[1], sbuf.st_size, "Loading", mi_hotfix_fullpath);
    close(p[1]);
    close(cpiofd);

    while ((r = waitpid(pid, &status, 0)) != pid) {
	if (r < 0 && errno == EINTR)  continue;
	if (r < 0)
	    mblog("load hotfix: waitpid report: %s\n", strerror(errno));
	else
	    mblog("load hotfix: waitpid return: %d\n", r);
    }
    umount_path(&re_ui);
    return 0;

  err_ret2:
    close(p[0]);
    close(p[1]);
  err_ret1:
    umount_path(&re_ui);
  err_ret0:
    return -1;
}

#endif

const char * loadre_runner(void) {
    int      readfd, writefd;
    ssize_t  misize;

    mblog("Load Run Environment: %s\n", mi_initrd_fullpath);
    if (!strncmp(mi_initrd_fullpath, "ftp:", strlen("ftp:")) ||
	!strncmp(mi_initrd_fullpath, "http:", strlen("http:"))) {
	pid_t   pid;
	int     p[2];

	if (pipe(p)) {
	    newtWinMessage("Error", "OK",
			   "Can't create pipe to contact with wget: %s.",
			   strerror(errno));
	    goto  err_ret0;
	}
	if ((pid = fork()) < 0) {
	    newtWinMessage("Error", "OK",
			   "Can't fork wget to fetch remote file: %s.",
			   strerror(errno));
	    goto  err_ret0;
	} else if (pid == 0) {
	    close(p[0]);
	    dup2(p[1], 1);
	    execl("/usr/bin/wget",
		  "/usr/bin/wget", "-q", "-O", "-", mi_initrd_fullpath, NULL);
	    exit(1);
	}
	close(p[1]);
	readfd = p[0];
    } else {
	readfd = open(mi_initrd_fullpath, O_RDONLY);
	if (readfd < 0) {
	    newtWinMessage("Error", "OK",
			   "Can't open %s for read: %s\n", strerror(errno));
	    goto  err_ret0;
	}
    }

    writefd = open(mi_initrd_device, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0666);
    if (writefd < 0) {
	newtWinMessage("Error", "OK",
		       "Can't open %s for write: %s\n", strerror(errno));
	goto  err_ret1;
    }
    misize = (ssize_t)miinitrd_size; /* * 1024 * 1024; */
    if (newt_copy_file(readfd, writefd, misize,
		  "Load the Full Running Environment", mi_initrd_file) < misize)
	goto  err_ret2;

    close(writefd);
    close(readfd);
/*
    if (mount(mi_initrd_device, mi_initrd_root, "ext2", MS_RDONLY, NULL)) {
	newtWinMessage("Error", "OK",
		       "Mount %s on %s as ext2 failed: %s",
		       mi_initrd_device, mi_initrd_root, strerror(errno));
	goto  err_ret2;
    }
    if (lomount(mi_initrd_cramfs_file, mi_initrd_cramfs_root, "cramfs")) {
	newtWinMessage("Error", "OK",
		       "Mount %s on %s failed: %s",
		       mi_initrd_cramfs_file, mi_initrd_cramfs_root, strerror(errno));
	goto  err_ret3;
    }
*/
    /* directly loop mount mi_initrd_device on mi_initrd_cramsfs_root as cramfs type */
    if (lomount(mi_initrd_device, mi_initrd_root, "cramfs") &&
        lomount(mi_initrd_device, mi_initrd_root, "squashfs")) {
	newtWinMessage("Error", "OK",
		       "Mount %s on %s failed: %s",
		       mi_initrd_device, mi_initrd_root, strerror(errno));
	goto  err_ret2;
    }
    if (re_ui_valid) {
	umount_path(&re_ui);
	re_ui_valid = 0;
    }
    return  NULL;
/*
    loumount(mi_initrd_cramfs_root);
 err_ret3:
    umount(mi_initrd_root);
*/
 err_ret2:
    close(writefd);
 err_ret1:
    close(readfd);
 err_ret0:
    if (re_ui_valid) {
	umount_path(&re_ui);
	re_ui_valid = 0;
    }
    return  "choose";
}

void loadre_saver(FILE *fp) {
}
